#ifndef RECETARIO
#define RECETARIO

#include <iostream>
#include <string>
#include "DiccTrie.h"
#include "ConjString.h"
#include "Multiconjunto.h"


using namespace std;

class Recetario {
	

public:
	// el constructor
	Recetario();
	// la asignación por copia (esto no afecta los órdenes propuestos en el trabajo de diseño en las funciones relevantes)
	Recetario &operator=(const Recetario &otro); 
	// agrega un ingrediente al recetario. Como siempre en el contexto de este trabajo, los nombres deben estar escritos en minúscula y 
	// ser alfabéticos (no se admiten numeros). Si el ingrediente ya estaba se devuelve false. Si es un ingrediente nuevo se devuelve true.
	bool agregarIngrediente( const string &ingrediente );
	// se agrega un plato al recetario. Se recibe el nombre de un plato y un conjunto de ingredientes. En caso de que los ingredientes no formen
	// parte del recetario, éste quedara como antes de llamar la función. Se devuelve true si se asignó el plato, y false en caso contrario.
	bool agregarPlato( const string &plato, const MConj &ingredientes );
	// devuelve el conjunto de platos definidos en el recetario.
	const ConjString& platos() const;
	// devuelve el conjunto de ingredientes del recetario.
	const ConjString& ingredientes() const;
	// devuelve los ingredientes necesarios para un pedido. El plato tiene que estar definido en el recetario.
	ConjString ingredientesNecesarios( const string &plato ) const;
	// devuelve la cantidad necesaria del ingrediente para hacer el plato.
	int cantidadNecesaria( const string &plato, const string &ingrediente) const;
	// devuelve la cantidad necesaria del ingrediente en un pedido de platos
	int cantidadNecesariaPedido( const MConj &ps, const string &ingrediente) const;
	// devuelve un multiconjunto con los ingredientes del pedido
	MConj ingredientesPedido(const MConj &pedido) const;
	// devuelve el conjunto (no el multiconjunto!) de los platos necesarios para hacer el pedido.
	ConjString ingredientesNecesariosPedido(const MConj &ps) const;

private:
	ConjString ingrs; // los ingredientes del recetario
	DiccTrie<MConj> recetas; // las recetas, es decir la asociación de un nombre de plato con un multiconjunto de ingredientes.
	
};


Recetario::Recetario() {
	ingrs = ConjString();
	recetas = DiccTrie<MConj>();
}
bool Recetario::agregarIngrediente( const string &ingrediente ) {

	bool retorno = false;
	if (!ingrs.pertenece(ingrediente)) {
		ingrs.agregar(ingrediente);
		retorno = true;
	}
	return retorno;
}

bool Recetario::agregarPlato( const string &plato, const MConj &ingredientes ) {
	bool retorno = false;
	if (ingredientes.mTieneTodos(ingrs)) {
		MConj m;
		m = ingredientes;
		recetas.definir(plato, m);
		
		retorno = true;
	}
	return retorno;
}

const ConjString& Recetario::ingredientes() const {
	return ingrs;

}

const ConjString& Recetario::platos() const {
	return recetas.claves();

}

ConjString Recetario::ingredientesNecesarios( const string &plato ) const{
	
	ConjString retorno;
	IteradorMConj it(recetas.obtener(plato));	
	while (it.tieneProximo()) {
		retorno.agregar(it.proximo());
	}



		
	return retorno;



	
}
int Recetario::cantidadNecesariaPedido( const MConj &ps, const string &ingrediente) const{
	
	string platoTemp;
	int resultado = 0;
	IteradorMConj it(ps);
	while (it.tieneProximo()) {
		platoTemp = it.proximo();
		resultado += cantidadNecesaria(platoTemp, ingrediente)*ps.mCantidad(platoTemp);
	}
	return resultado;
}

int Recetario::cantidadNecesaria( const string &plato, const string &ingrediente) const {

	
	return recetas.obtener(plato).mCantidad(ingrediente);

}

MConj Recetario::ingredientesPedido(const MConj &pedido) const {

	MConj retorno;	
	string pl;
	string ingred;
	IteradorMConj it(pedido);
	IteradorConjString it2;
	ConjString c;

	while (it.tieneProximo()) {
		pl = it.proximo();
		ConjString c(ingredientesNecesarios(pl));
		it2 = IteradorConjString(c);
		while (it2.tieneProximo()) {
				ingred = it2.proximo();
				retorno.mAgregarN(ingred, cantidadNecesaria(pl, ingred)*pedido.mCantidad(pl));
		}
	}


	return retorno;
}

Recetario & Recetario::operator=(const Recetario &otro) {

	if (this != &otro) {
			ingrs = otro.ingrs;
			recetas = otro.recetas;
		}
		
		return *this;

}

ConjString Recetario::ingredientesNecesariosPedido(const MConj &ps) const {
	ConjString retorno;
	MConj aux;
	aux = ingredientesPedido(ps);
	IteradorMConj m(aux);
	while (m.tieneProximo()) {
		retorno.agregar(m.proximo());
	}

	return retorno;
	
	
}

#endif
